﻿using System;

using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Silvermoon.Windows;
using Silvermoon.UI;
using Silvermoon.Utils;

namespace Silvermoon.Controls.Beta
{
    public class ItemBase : CompositeControlBase
    {
        #region static

        public static readonly PropertyAccessor<ItemBase, int> BackgroundOpacityProperty = PropertyAccessor.Register<ItemBase, int>("",
            c => c.BackgroundOpacity,
            (c, v) => c.BackgroundOpacity = v);

        /// <summary>
        /// Initializes the <see cref="ItemBase"/> class.
        /// </summary>
        static ItemBase()
        {
            VisualStateManager manager = new VisualStateManager(
                Control.OpacityDisabledEnabledGroup,
                new VisualStateGroup(
                    new VisualState(VState.Unselected, 500),
                    new VisualState(VState.Selected,
                        new ColorTransition { Property = TextColorProperty, Duration = 100, To = PhoneColors.Accent })
                    ),
                new VisualStateGroup(
                    new VisualState(VState.Normal, 500),
                    new VisualState(VState.Pressed,
                    new FloatTransition { Property = YRotationProperty, To = -3f, Duration = 5 },
                    new ScaleTransition { To = new ScaleTransform(0.94f, 0.94f, 1f), Duration = 2 }
                    )
                 )
            );
            VisualStateManager.RegisterClassManager(typeof(ItemBase), manager);
        }

        public static readonly PropertyAccessor<ItemBase, float> YRotationProperty = PropertyAccessor.Register<ItemBase, float>(
            "YRotation",
            (c) => c.rotation.Angle,
            (c, v) => { c.rotation.Angle = v; c.Invalidate(InvalidationFlag.Transformation); });

        #endregion
        #region ctor

        protected RotateTransform rotation;


        /// <summary>
        /// Initializes a new instance of the <see cref="ItemBase"/> class.
        /// </summary>
        public ItemBase()
            : base()
        {
            Size = new Size(0, 64);
            rotation = new RotateTransform { Axis = RotateAxis.YAxis, OrigX = 1f };
            Transformation += rotation;
        }

        #endregion
        #region fields;

        private bool isPressed;
        private bool isSelected;

        #endregion
        #region props

        public int ItemIndex { get; internal set; }

        public bool IsPressed
        {
            get { return isPressed; }
            set
            {
                if (isPressed != value)
                {
                    isPressed = value;
                    Invalidate(InvalidationFlag.LayoutAppearance);
                    SetState(value ? VState.Pressed : VState.Normal);
                }
            }
        }

        public bool IsSelected
        {
            get { return isSelected; }

            internal set
            {
                if (isSelected != value)
                {
                    isSelected = value;
                    OnSelectedChanged();
                    Invalidate(InvalidationFlag.Appearance);
                }
            }
        }

        public int BackgroundOpacity
        {
            get { return Background != null ? Background.Opacity : 0; }
            set
            {
                if (Background != null)
                {
                    Background.Opacity = value;
                    Invalidate(InvalidationFlag.Appearance);
                }
            }
        }

        /// <summary>
        /// for internal use only.
        /// </summary>
        internal int AnimatedOffset { get; set; }

        internal protected IItemCollection Collection { get; internal set; }

        public ListBoxBase ListBox
        {
            get
            {
                IItemCollection collection = Collection;
                return collection != null ? collection.GetListBox() : null;
            }
        }

        public ItemGroupBase ItemGroup
        {
            get
            {
                IItemCollection collection = Collection;
                return collection != null ? collection.GetItemGroup() : null;
            }
        }

        #endregion
        #region events

        /// <summary>
        /// Notifies an item to update it's properties. This method usually occurs when it gets visible inside a <see cref="ListBox"/> or
        /// when the listbox has changed properties that also affect items inside.
        /// </summary>
        public event EventHandler UpdateProperties;

        #endregion
        #region methods

        public override void BringIntoView(bool animated)
        {
            if (Parent != null)
            {
                Parent.BringIntoView(this.Bounds, animated);
            }
            else
            {
                if (this.ItemGroup != null) this.ItemGroup.BringItemIntoView(this, animated);
                else if (this.ListBox != null) this.ListBox.BringItemIntoView(this, animated);

            }
        }

        protected internal override void OnTouchDown(TouchEventArgs e)
        {
            if (!e.Handled)
            {
                IsPressed = true;
            }
            base.OnTouchDown(e);
            e.Handled = true;
        }

        protected internal override void OnTouchUp(TouchEventArgs e)
        {
            IsPressed = false;
            base.OnTouchUp(e);
            e.Handled = true;
        }

        protected virtual void OnSelectedChanged()
        {
            SetState(isSelected ? VState.Selected : VState.Unselected);
        }

        protected internal override void OnTap(TapEventArgs e)
        {
            base.OnTap(e);
            if (!e.Handled)
            {
                ICommand cmd = Command;
                if (cmd != null) RaiseCommand(cmd);
            }
            e.Handled = true;
        }

        protected override void OnSizeChanging(Size oldValue)
        {
            base.OnSizeChanging(oldValue);
            if (ListBox != null)
            {
                if (oldValue.Height != Height) ListBox.ItemHeightChanged(this);
            }
        }

        /// <summary>
        /// Occurs when the item is animated.
        /// </summary>
        /// <param name="animationType">Type of animation.</param>
        /// <param name="progress">Progress of animation which is between 0 and maxProgress.</param>
        /// <param name="maxProgress">Maximum value for progress.</param>
        public virtual void SetAnimationState(ItemAnimationType animationType, int progress, int maxProgress, ref Rectangle bounds)
        {
            switch (animationType)
            {
                case ItemAnimationType.Insert:
                    Opacity = 255 * progress / maxProgress;
                    break;
                case ItemAnimationType.Remove:
                    Opacity = 255 * (maxProgress - progress) / maxProgress;
                    break;
                case ItemAnimationType.None:
                    Opacity = 255;
                    break;
            }
        }

        /// <summary>
        /// Notifies an item to update it's properties. This method usually occurs when it gets visible inside a <see cref="ListBox"/> or
        /// when the listbox has changed properties that also affect items inside.
        /// </summary>
        public virtual void OnUpdateProperties()
        {
            if (UpdateProperties != null) UpdateProperties(this, EventArgs.Empty);
        }


        #endregion


    }
}
